package com.example.webshiro.shiro.realm;

import com.example.webshiro.common.constant.CommonConstant;
import com.example.webshiro.common.utils.JwtUtil;
import com.example.webshiro.common.utils.RedisUtil;
import com.example.webshiro.shiro.JwtToken;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.stereotype.Service;
import java.util.HashSet;
import java.util.Set;

/**
 * <p>jwtRealm</p>
 * @author LuoYu
 * 2021/4/11
 **/
@Service
@Slf4j
public class JwtUserRealm extends AuthorizingRealm {



    @Override
    public boolean supports(AuthenticationToken authenticationToken) {
        return authenticationToken instanceof JwtToken;
    }


    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        log.info("用户授权....");
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        Long userId = JwtUtil.getLongClaim(principalCollection.toString(), "userId");
        //TODO: 查询用户权限  Jpa切换为Mybatis后实现
        info.addRole("admin");
        Set<String> permissionList = new HashSet<>();
        permissionList.add("add");
        permissionList.add("delete");
        info.setStringPermissions(permissionList);
        return info;
    }

    /**
     * 认证
     * @param authenticationToken  token信息
     * @return                      认证完毕后的信息
     * @throws AuthenticationException   认证异常
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        log.info("用户认证....");
          String token = (String) authenticationToken.getCredentials();
          Long  userId = JwtUtil.getLongClaim(token, "userId");
        if(userId == null) {
            log.warn("用户认证 ----> Token中未获取到用户信息");
            throw new AuthenticationException("Token中未携带用户信息");
        }
        //TODO: 查询用户信息  Jpa切换为Mybatis后实现
        log.info("用户执行认证 ----> 用户ID:{}",userId);
        String key = CommonConstant.currentRedisPreKey.concat(String.valueOf(userId));
        String value = RedisUtil.get(key);
        try {
            boolean verify = JwtUtil.verify(token);
            if (!verify) {
                log.error("用户身份已过期 ----> account:{}", userId);
                throw new AuthenticationException("token校验失败");
            }
        }catch (Exception e){
            throw new AuthenticationException(e.getMessage());
        }
        //校验是否已经过期
        if(value == null){
            log.error("用户身份已过期或者已占用 ----> account:{}",userId);
            throw new AuthenticationException("身份已过期");
        }
        //校验是否已经被异地登录
        String uuid = JwtUtil.getStringClaim(token, "uuid");
        if(!uuid.equals(value)){
            log.error("用户已下线 ----> account:{}",userId);
            throw new AuthenticationException("身份已过期");
        }
        //重新设置用户会话时间
        RedisUtil.setExpireTime(key,1800);
        return new SimpleAuthenticationInfo(token,token,"userRealm");
    }
}
